package cn.cdeden.resource.unified.service.impl;

import cn.cdeden.common.core.exception.ServiceException;
import cn.cdeden.common.core.utils.page.TableDataInfo;
import cn.cdeden.common.mybatis.core.page.PageQuery;
import cn.cdeden.common.oss.core.OssClientBucket;
import cn.cdeden.common.oss.entity.UploadResult;
import cn.cdeden.common.oss.enumd.OssModuleType;
import cn.cdeden.common.oss.factory.OssFactory;
import cn.cdeden.resource.api.domain.RemoteFile;
import cn.cdeden.resource.domain.SysOss;
import cn.cdeden.resource.domain.bo.SysOssDownloadRecordBo;
import cn.cdeden.resource.domain.SysOssEs;
import cn.cdeden.resource.domain.vo.*;
import cn.cdeden.resource.service.*;
import cn.cdeden.resource.unified.domain.OnlineConfig;
import cn.cdeden.resource.unified.domain.dto.FilesEditingDto;
import cn.cdeden.resource.unified.domain.dto.OnlinePreviewInfoDto;
import cn.cdeden.resource.unified.domain.enums.PreviewTypeEnums;
import cn.cdeden.resource.unified.domain.vo.FilePreviewVo;
import cn.cdeden.resource.unified.enums.EditorEnums;
import cn.cdeden.resource.unified.service.UnifiedFileService;
import cn.cdeden.system.api.RemoteUserService;
import cn.cdeden.system.api.model.LoginUser;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.logging.log4j.util.Base64Util;
import org.apache.tika.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;


import java.io.*;
import java.util.*;


import java.io.IOException;

/**
 * @ProjectName : KnowCore01
 * @Package : cn.cdeden.resource.unified.service.impl
 * @ClassName : UploadFileServiceImpl
 * @Author : Yu.
 * @Description : // TODO
 * @Date : 2024/12/5 14:00
 * @Version : 1.0
 */

@RequiredArgsConstructor
@Service
@Slf4j
public class UnifiedFileServiceImpl implements UnifiedFileService {

    private final ISysOssService ossService;

    private final ISysOssVersionService ossVersionService;

    private final OnlineConfig captchaProperties;


    private final ISysOssDownloadRecordService downloadService;  //下载记录


    private final ISysOssRecentlyViewedService viewedService; //浏览记录

    private final ISysOssSliceService ossSliceService; //分片上传

    @Autowired(required = false)
    private OssFileEsService ossFileEsService; //es搜索服务


    @DubboReference
    private final RemoteUserService userService;



    @Override
    public SysOssVo editSave(InputStream stream, FilesEditingDto editingDto, EditorEnums type) {
        //走不同的实现
        String id = editingDto.getStorageId();
        Long userId = editingDto.getUserId();
        String username = editingDto.getUsername();
        if (userId == null) {
            LoginUser user = userService.getUserInfo(userId);
            if (ObjectUtils.isEmpty(user)) {
                throw new ServiceException("用户不存在");
            }
        }
        SysOss sysOss = ossService.getById(id);

        OssModuleType typeEnum = editingDto.getTypeEnum(); ////获取 文件模块
        byte[] byteArray = null;
        try {
            byteArray = IOUtils.toByteArray(stream);
        } catch (IOException e) {
            throw new ServiceException();
        }
        MultipartFile file = new MockMultipartFile(sysOss.getOriginalName() + "." + sysOss.getFileSuffix(), byteArray);


        String suffix = editingDto.getSuffix();
        OssClientBucket storage = OssFactory.instanceBucket(sysOss.getService());
        //保存文件信息
        UploadResult uploadResult = storage.uploadSuffix(byteArray, suffix, file.getContentType(), sysOss.getBucketName(), sysOss.getFileName());
        SysOssVo sysOssVo = ossService.update(Long.valueOf(id), uploadResult, typeEnum, userId);
        return sysOssVo;
    }



    /**
     * 获取文件的预览信息
     *
     * @param dataInfo
     * @param info
     * @return cn.cdeden.resource.unified.domain.vo.FilePreviewVo
     * @author Yu.
     * @Description //
     * @Date 2024/12/8 16:57
     **/
    @Override
    public FilePreviewVo getFileDataInfo(RemoteFile dataInfo, OnlinePreviewInfoDto info) {
        SysOssVo sysOssVo = ossService.getByIdAndVersionId(dataInfo.getOssId(), dataInfo.getVersionId());
        String previewType = info.getPreviewType();
        PreviewTypeEnums code = PreviewTypeEnums.findCode(previewType);
        //获取链接
        OssClientBucket storage = OssFactory.instanceBucket(sysOssVo.getService()); //获取存储服务
        String privateUrl = storage.getPrivateUrl(sysOssVo.getBucketName(), sysOssVo.getFileName(), sysOssVo.getVersionId(), 60 * 60);


        String previewServer; //文件的预览服务器地址
        // 根据预览类型获取预览服务器地址 处理链接数据
        switch (code) {
            case write:
                previewServer = captchaProperties.getWrite();
                break;
            case onlyOffice:
                previewServer = captchaProperties.getOnlyOffice();
                break;
            case iceblue:
                previewServer = captchaProperties.getIceblue();
                break;
            case kkFileView:
            default: {
                previewServer = captchaProperties.getKkFileView();
                previewType = PreviewTypeEnums.kkFileView.getCode();
                privateUrl = previewServer + "/onlinePreview?url=" + Base64Util.encode(privateUrl); // 转码
            }
        }


        String watermarkTxt = null;


        if (info.isRecord()) {
            viewedService.save(sysOssVo, info);   //添加记录
        }

        return FilePreviewVo.builder() //构建预览信息
            .preview(previewType)
            .fileSuffix(dataInfo.getFileSuffix())
            .previewServer(previewServer)
            .fileName(dataInfo.getOriginalNameInfo())
            .fileSize(dataInfo.getFileSize())
            .watermarkTxt(watermarkTxt)
            .url(privateUrl)
            .versionName(sysOssVo.getVersionName())
            .versionId(sysOssVo.getVersionId())
            .edit(dataInfo.isEdit())
            .download(dataInfo.isDownload())
            .read(dataInfo.isRead())
            .print(dataInfo.isPrint())
            .build();
    }

    @Override
    public TableDataInfo<SysOssVersionVo> getFilesVersions(RemoteFile dataInfo, OnlinePreviewInfoDto info, PageQuery pageQuery) {
        TableDataInfo<SysOssVersionVo> byIdPage = ossVersionService.getByIdPage(dataInfo.getOssId(), pageQuery);
        return byIdPage;
    }

    /**
     * 获取文件的下载记录
     *
     * @param dataInfo
     * @param info
     * @param pageQuery
     * @return
     */
    @Override
    public TableDataInfo<SysOssDownloadRecordVo> getFilesDownloadRecord(RemoteFile dataInfo, OnlinePreviewInfoDto info, PageQuery pageQuery) {
        return downloadService.selectRecordPage(
            SysOssDownloadRecordBo.builder()
                .ossId(String.valueOf(dataInfo.getOssId()))
                .moduleType(info.getType())
                .build(),
            pageQuery);
    }



    @Override
    public Boolean deleteByIdAndVersionId(Long id, String versionId) {
        SysOssVo sysOss = ossService.getById(id);
        if (ObjectUtil.isNull(sysOss)) {
            throw new ServiceException("删除的文件数据不存在!");
        }
        OssClientBucket storage = OssFactory.instanceBucket(sysOss.getService());
        SysOssVersionVo byIdAndVersionId = ossVersionService.getByIdAndVersionId(id, versionId);
        if (ObjectUtil.isNull(byIdAndVersionId)) {
            throw new ServiceException("删除的文件版本不存在!");
        } else {
//            更新版本信息
            List<SysOssVersionVo> byIdList = ossVersionService.getByIdList(id);
            if (byIdList.size() == 1) { //只有一个版本 直接删除 文件记录 和文件
                ossService.removeById(id);
                storage.delete(sysOss.getBucketName(), sysOss.getUrl());
                String esId = sysOss.getEsId();
                if (ObjectUtil.isNotNull(esId)) {
                    try {
                        ossFileEsService.deleteById(esId);
                    } catch (Exception e) {
                        log.error("删除es文件失败", e);
                    }
                }
                return true;
            } else {  //多个版本  删除版本然后
                //删除文件
                storage.delete(sysOss.getBucketName(), sysOss.getUrl(), versionId);
                Boolean b = ossVersionService.deleteByOssIdAndVersionId(id, versionId);
                SysOssVersionVo sysOssVersionVo = byIdList.get(1); //获取上一个版本
                ossService.lambdaUpdate()
                    .eq(SysOss::getOssId, id)
                    .set(SysOss::getVersionId, sysOssVersionVo.getVersionId()) //版本id
                    .set(SysOss::getVersionName, sysOssVersionVo.getVersionName()) //版本名称
                    .set(SysOss::getFileSize, sysOssVersionVo.getFileSize()) //文件大小
                    .set(SysOss::getFileMd5, sysOssVersionVo.getFileMd5()) //文件的MD5
                    .set(SysOss::getService, sysOssVersionVo.getService()) //更新服务供应商
                    .update();
                // oss更新 版本信息
                if (sysOss.getVersionId().equals(versionId)) {
                    sysOss.setVersionId(sysOssVersionVo.getVersionId());
                    sysOss.setVersionName(sysOssVersionVo.getVersionName());
                    sysOss.setFileSize(sysOssVersionVo.getFileSize());
                    sysOss.setFileMd5(sysOssVersionVo.getFileMd5());
                    sysOss.setService(sysOssVersionVo.getService());
                    //处理es 文件类容数据
                    esUpdateFileInfo(sysOss);
                }
                return b;
            }
        }

    }





    /**
     * 上传文件根据文件类型 上传文件信息 到es中去
     *
     * @param ossVo     文件基本信息
     * @param fileBytes 文件字节流
     * @return void
     * @author Yu.
     * @Date 2024/12/11 15:31
     **/
    @Async
    @Override
    public void esInsertFileInfo(SysOssVo ossVo, byte[] fileBytes) {

        String fileSuffix = ossVo.getFileSuffix();

        String content = Base64.getEncoder().encodeToString(fileBytes);
        String uuid = IdUtil.simpleUUID();

        SysOssEs build = SysOssEs.builder()
            .id(uuid)
            .content(content) //文档内容
            .ossId(String.valueOf(ossVo.getOssId())) //文件id
            .tenantId(ossVo.getTenantId()) //租户id
            .moduleId(ossVo.getModuleId()) //文件模块id
            .type(FileTypeEnum.FILE.getCode()) //文件类型
            .moduleType(ossVo.getModuleTypeInfo().getCode()) //文件模块类型
            .title(ossVo.getOriginalName())
            .fileSuffix(fileSuffix)
            .versionId(ossVo.getVersionId())
            .versionName(ossVo.getVersionName())
            .createDept(ossVo.getCreateDept())
            .createBy(ossVo.getCreateBy()) //创建人
            .createTime(ossVo.getCreateTime()) //创建时间
            .updateBy(ossVo.getUpdateBy())
            .updateTime(ossVo.getUpdateTime())
//            .userIdList(Arrays.asList(String.valueOf(ossVo.getCreateBy()))) //创建人id
            .userIdList(ossVo.getEsPurview().getUserIdList())
            .roleIdList(ossVo.getEsPurview().getRoleIdList())
            .deptIdList(ossVo.getEsPurview().getDeptIdList())
            .postIdList(ossVo.getEsPurview().getPostIdList())
            .build();
        String esId = ossVo.getEsId();
        if (ObjectUtil.isNotNull(esId)) {
            build.setId(esId);
            try {
                ossFileEsService.deleteById(esId);
            } catch (Exception e) {
                log.error("删除es文件失败", e);
            }
        } else {
            //更新文件es主键
            ossService.lambdaUpdate().set(SysOss::getEsId, uuid).eq(SysOss::getOssId, ossVo.getOssId()).update();
        }
        try {
            ossFileEsService.insert(build);
        } catch (Exception e) {
            log.error("添加es文件失败", e);
        }


        String moduleType = build.getModuleType();
        OssModuleType coedInfo = OssModuleType.findCoedInfo(moduleType);
        switch (coedInfo) {
            case Temporary:
            case Team:
            case public_images:
            default:
                return;
            case Enterprise:
//                enterpriseFileService.updateEs(build.getModuleId(),build.getId());
                break;
            case Personal:
        }


    }

    /**
     * 上传文件根据文件类型 上传文件信息 到es中去
     *
     * @param ossVo
     * @return void
     * @author Yu.
     * @Date 2024/12/11 15:31
     **/
    @Async
    @Override
    public void esUpdateFileInfo(SysOssVo ossVo) {
        OssClientBucket storage = OssFactory.instanceBucket(ossVo.getService());
        try {

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            long download = storage.downloadAsynchronous(ossVo.getBucketName(), ossVo.getFileName(), ossVo.getVersionId(), outputStream);
            String content = Base64.getEncoder().encodeToString(outputStream.toByteArray());
            SysOssEs build = SysOssEs.builder()
                .id(ossVo.getEsId()) //es主键
                .content(content) //文档内容
                .ossId(String.valueOf(ossVo.getOssId())) //文件id
                .tenantId(ossVo.getTenantId()) //租户id
//                .moduleId(ossVo.getModuleId()) //文件模块id
                .type(FileTypeEnum.FILE.getCode()) //文件类型
                .moduleType(ossVo.getModuleTypeInfo().getCode()) //文件模块类型
                .title(ossVo.getOriginalName())
                .fileSuffix(ossVo.getFileSuffix())
                .versionId(ossVo.getVersionId())
                .versionName(ossVo.getVersionName())
                .createDept(ossVo.getCreateDept())
                .createBy(ossVo.getCreateBy()) //创建人
                .createTime(ossVo.getCreateTime()) //创建时间
                .updateBy(ossVo.getUpdateBy())
                .updateTime(ossVo.getUpdateTime())
                .build();
            ossFileEsService.updateById(build);
        } catch (Exception e) {
            log.error("es更新异常", e);
        }
    }

    @Getter
    @AllArgsConstructor
    public enum FileTypeEnum {
        FOLDER("folder", "文件夹"),
        FILE("file", "文件"),
        ;
        private final String code;
        private final String text;
    }


}
